package com.tengju.user.domain.model.sign;

import com.fasterxml.jackson.core.type.TypeReference;
import com.tengju.user.domain.model.user.Staff;
import com.tengju.user.domain.model.user.UserIdCode;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import com.tengju.user.domain.shared.JsonUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

@Getter
@AllArgsConstructor
//todo 实体拆分
@Slf4j
public class StarSignInfo {

    private SignId id;

    private UserIdCode idCode;

    private Integer beforeStarRole;

    private Integer beforeStarLevel;

    private Integer starRole;

    private Integer starLevel;

    private Integer triggerType;

    private LocalDateTime inviteDate;

    private Integer accountType;

    private Integer step;

    private LocalDateTime auditTime;

    private Integer indicatorRequireStat;

    private Integer auditStat;

    private String auditDesc;

    private LocalDateTime expireDate;

    private String invalidDesc;

    private String changeRecord;

    private String createBy;

    private String auditBy;

    private String updateBy;


    public void finishSign(Staff staff) {
        changeStepTo(StarSignStepEnum.END);
        this.updateBy = staff.getName();
    }

    public void stopSign(Staff staff) {
        changeStepTo(StarSignStepEnum.TERMINATED);
        this.updateBy = staff.getName();
    }

    public void updateAudit(String auditDesc, Integer auditStatus, Staff staff) {
        if (!this.isAlreadyPassAccountStep()) {
            log.warn("星级签约还未处于身份认证完结，审核失败，idCode:{}，curStep:{}", idCode, step);
            throw new StarSignException(
                    String.format("用户:%s 星级签约还未处于身份认证完结状态，审核失败,curStep:%s", idCode, step));
        }
        this.auditDesc = auditDesc;
        this.auditStat = auditStatus;
        this.auditBy = staff.getName();
        this.auditTime = LocalDateTime.now();
        if (StarAuditStatEnum.PASS_AUDIT.getCode() == auditStatus) {
            changeStepTo(StarSignStepEnum.AUDIT_ALREADY);
        }
        this.updateBy = staff.getName();
    }

    public void submitSurvey() {
        changeStepTo(StarSignStepEnum.SURVEY_ALREADY);
    }

    public void startAudit(Integer accountType, int indicatorRequireStat) {
        changeStepTo(StarSignStepEnum.ACCOUNT_ALREADY);
        this.auditStat = StarAuditStatEnum.WAIT_AUDIT.getCode();
        this.accountType = accountType;
        this.indicatorRequireStat = indicatorRequireStat;
    }

    public void finishSign() {
        changeStepTo(StarSignStepEnum.END);
    }

    public void passSign() {
        changeStepTo(StarSignStepEnum.SIGN_ALREADY);
    }

    public StarSignInfo(UserIdCode idCode, Integer starRole, Integer starLevel,
            Integer targetStarRole, Integer targetStarLevel, int triggerType, LocalDateTime now,
            Staff staff) {
        this.idCode = idCode;
        this.beforeStarRole = starRole;
        this.beforeStarLevel = starLevel;
        this.starRole = targetStarRole;
        this.starLevel = targetStarLevel;
        this.triggerType = triggerType;
        this.inviteDate = now;
        this.step = StarSignStepEnum.SEND_ALREADY.getStep();
        this.createBy = staff.getName();
        this.updateBy = staff.getName();
    }

    public void expireDate(Integer signExpireDay) {
        this.expireDate = this.inviteDate.plusDays(signExpireDay + 1L)
                .withHour(0)
                .withMinute(0)
                .withSecond(0)
                .withNano(0);
    }

    public boolean isAlreadyPassAccountStep() {
        return StarSignStepEnum.ACCOUNT_ALREADY.getStep() == this.step;
    }

    public void passExam() {
        changeStepTo(StarSignStepEnum.EXAM_ALREADY);
    }

    public void changeStepTo(StarSignStepEnum step) {
        StarSignStepEnum curStepEnum = StarSignStepEnum.getByStep(this.getStep());
        if (canChangeStepTo(step)) {
            this.step = step.getStep();
            changeRecord(step);
        } else {
            throw new StarSignException(String.format("流程提交不合法，现有流程：%s。", curStepEnum.getDesc()));
        }
    }

    private void changeRecord(StarSignStepEnum step) {
        Map<String, Object> maps = Optional.ofNullable(JsonUtil.toMap(this.changeRecord, new TypeReference<>() {
        })).orElse(new HashMap<>());
        maps.put(step.toString(), LocalDateTime.now());
        this.changeRecord = JsonUtil.toJSONString(maps);
    }

    public boolean canChangeStepTo(StarSignStepEnum step) {
        if (step == null) {
            return false;
        }
        switch (step) {
            case SEND_ALREADY:
                return false;
            case SURVEY_ALREADY:
                return this.step == StarSignStepEnum.SEND_ALREADY.getStep();
            case ACCOUNT_ALREADY:
                return this.step == StarSignStepEnum.SURVEY_ALREADY.getStep();
            case AUDIT_ALREADY:
                return this.step == StarSignStepEnum.ACCOUNT_ALREADY.getStep();
            case EXAM_ALREADY:
                return this.step == StarSignStepEnum.AUDIT_ALREADY.getStep();
            case SIGN_ALREADY:
                return this.step == StarSignStepEnum.EXAM_ALREADY.getStep();
            case END:
                return this.step == StarSignStepEnum.SIGN_ALREADY.getStep();
            case TERMINATED:
                return this.step != StarSignStepEnum.END.getStep();
        }
        return false;
    }
}
